<?php
/**
 * This file is part of Hyperf Mall.
 *
 * @link     https://gitee.com/scwlkj/hyperf_mall
 * @contact  hyperf_mall@163.com
 */

namespace App\Repository;

use App\Common\OidBuild;
use App\Constants\AfterSaleConstants;
use App\Constants\OrderConstant;
use App\Exception\BaseException;
use App\Model\AfterSaleModel;
use App\Service\Member\MemberBalanceService;
use App\Service\Member\MemberService;
use App\Utils\DB;
use App\Utils\Log;
use Hyperf\Di\Annotation\Inject;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Swoole\Exception;

class AfterSaleRepository extends BaseRepository
{
    /**
     * @Inject
     * @var AfterSaleModel
     */
    protected $model;

    /**
     * @Inject
     * @var OidBuild
     */
    protected OidBuild $oidBuild;

    /**
     * @Inject
     * @var AfterDetailRepository
     */
    protected AfterDetailRepository $afterDetailRepository;

    /**
     * @Inject
     * @var AfterLogRepository
     */
    protected AfterLogRepository $afterLogRepository;

    /**
     * @Inject
     * @var OrderRefundsRepository
     */
    protected OrderRefundsRepository $orderRefundsRepository;

    /**
     * @Inject
     * @var AfterDrawbackRepository
     */
    protected AfterDrawbackRepository $afterDrawbackRepository;

    /**
     * @Inject
     * @var OrderRepository
     */
    protected OrderRepository $orderRepository;

    /**
     * @Inject
     * @var OrderDetailRepository
     */
    protected OrderDetailRepository $orderDetailRepository;

    /**
     * @inject
     * @var MemberService
     */
    protected MemberService $memberService;

    /**
     * @Inject
     * @var MemberBalanceService
     */
    protected MemberBalanceService $memberBalanceService;

    /**
     * Notes: 售后申请
     * Author: Bruce.z
     * DateTime: 2022/8/18 15:24
     * @param $data
     * @return bool
     * @throws BaseException
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function baseAdd($data): bool
    {
        $re = [
            'number'=>$this->oidBuild->getAfterNumber(),
            'oid'=>$data['oid'],
            'member_id'=>$data['member_id'],
            'remark'=>$data['description'],
            'reason'=>$data['reason'],
            'image'=>$data['image']?serialize($data['image']) : '',
        ];

        $order_detail = $this->orderDetailRepository->getOne(['id'=>$data['order_detail_id']], ['id','goods_name','product_image','spec','retail_price','num','total_price']);

        $member = $this->memberService->getOne(['id'=>$data['member_id']], ['id','username','tel']);

        $detail = [
            'goods_id'=>$data['goods_id'],
            'product_id'=>$data['product_id'],
            'order_detail_id'=>$data['order_detail_id'],
            'member_id'=>$data['member_id'],
            'goods_name'=>$order_detail['goods_name']??'',
            'goods_spec'=>$order_detail['spec']??'',
            'image'=>$order_detail['product_image']??'',
            'price_sell'=>$order_detail['retail_price']??0,
            'price'=>$order_detail['total_price']??0,
            'total_price'=>$order_detail['total_price']??0,
            'nums'=>$order_detail['num']??0,
            'send_nums'=>$order_detail['num']??0,
            'back_nums'=>$order_detail['back_nums']??0,
        ];

        $after_draw_back = [
            'back_status' => AfterSaleConstants::AFTER_MARKET_PART,
            'oid' => $data['oid'],
            'back_money' => $data['return_money'],
            'total_cost_price' => $order_detail['total_price'],
            'goods_price' => $order_detail['total_price'],
        ];

        $log = [
            'oid' => $data['oid'],
            'user_id' => $data['member_id'],
            'username' => $member['username'],
            'log_content' => '用户发起售后！',
            'log_type' => AfterSaleConstants::LOG_TYPE_USER,
            'handle_type' => AfterSaleConstants::HANDLE_TYPE_APPLY,
            'log_remark' => $data['reason'],
            'create_time' => time(),
        ];

        DB::beginTransaction();
        try {
            $after = parent::baseAdd($re);

            $detail['after_id'] = $after['id'];
            $this->afterDetailRepository->baseAdd($detail);

            $after_draw_back['after_id'] = $after['id'];
            $this->afterDrawbackRepository->baseAdd($after_draw_back);

            $log['after_id'] = $after['id'];
            $this->afterLogRepository->baseAdd($log);

            $this->orderRepository->updateByConditions(['oid'=>$data['oid']], [
                'after_status'=>OrderConstant::ORDER_AFTER_STATUS_MIDDLE,
                'after_status_two'=>OrderConstant::ORDER_AFTER_STATUS_MIDDLE,
            ]);

            $this->orderDetailRepository->updateByConditions(['id' => $data['order_detail_id']], [
                'after_status' => OrderConstant::ORDER_AFTER_STATUS_MIDDLE,
                'after_status_two' => OrderConstant::ORDER_AFTER_STATUS_MIDDLE
            ]);

            DB::commit();
        }catch (Exception $e){
            DB::rollBack();
        }

        return true;
    }

    /**
     * Notes: C端我的售后列表
     * Author: Bruce.z
     * DateTime: 2022/8/19 9:46
     * @param array $data
     * @return array
     */
    public function appList(array $data): array
    {
        $condition = [
            'member_id'=>$data['member_id']
        ];
        $field = ['number','oid','status','create_time','id'];
        $res = $this->getPageRows($condition,$field, $data['page'], $data['size']);

        if(count($res['data'])){
            $after_ids = array_column($res['data'], 'id');

            $details = $this->afterDetailRepository->getRows(['after_id'=>$after_ids] ,['id','after_id','goods_name','goods_spec','price_sell','nums','price','create_time','image']);

            $drawbacks = $this->afterDrawbackRepository->getRows(['after_id'=>$after_ids] ,['back_money','status','after_id']);
            $drawbacks = array_column($drawbacks, null, 'after_id');

            foreach ($res['data'] as &$re){
                $re['drawback'] = $drawbacks[$re['id']] ?? [];
                $re['detail'] = array_filter($details, function ($v) use ($re){return $v['after_id'] == $re['id'];});
            }
        }

        return $res;
    }

    /**
     * Notes: 退款详情
     * Author: Bruce.z
     * DateTime: 2022/8/19 10:19
     * @param $number
     * @return array
     * @throws BaseException
     */
    public function appDetail($number): array
    {
        $re = $this->getOne(['number'=>$number],['number','oid','status','create_time','id','audit_time','image','cause','remark','reason']);
        if(empty($re)){
            throw new BaseException(BaseException::BASE_ERROR, '退款单不存在');
        }
        $re['detail'] = $this->afterDetailRepository->getRows(['after_id'=>$re['id']] ,['id','after_id','goods_name','goods_spec','price_sell','nums','price','create_time','image']);
        $re['drawback'] = $this->afterDrawbackRepository->getOne(['after_id'=>$re['id']] ,['back_money','status','after_id']);

        $re['log'] = $this->afterLogRepository->getRows(['after_id'=>$re['id']], ['username','log_content','log_remark','create_time']);
        $re['image'] = $re['image'] ? unserialize($re['image']) : [];
        $re['create_time'] = date('Y-m-d H:i:s', $re['create_time']);
        $re['audit_time'] = $re['audit_time'] ? date('Y-m-d H:i:s', $re['audit_time']) : '';
        return $re;
    }

    /**
     * Notes: A端 售后订单列表
     * Author: Bruce.z
     * DateTime: 2022/8/19 17:39
     * @param $data
     * @return array
     */
    public function list($data): array
    {
        $condition = [];
        if(!empty($data['oid'])){
            $condition[] = ['oid','like','%'.$data['oid'].'%'];
        }

        if(!empty($data['number'])){
            $condition[] = ['number','like','%'.$data['number'].'%'];
        }

        $field = ['number','oid','status','create_time','id'];
        $res = $this->getPageRows($condition,$field, $data['page'], $data['size']);

        if(count($res['data'])){
            $after_ids = array_column($res['data'], 'id');

            $details = $this->afterDetailRepository->getRows(['after_id'=>$after_ids] ,['id','after_id','goods_name','goods_spec','price_sell','nums','price','create_time','image']);

            $drawbacks = $this->afterDrawbackRepository->getRows(['after_id'=>$after_ids] ,['back_money','status','after_id']);
            $drawbacks = array_column($drawbacks, null, 'after_id');

            foreach ($res['data'] as &$re){
                $re['drawback'] = $drawbacks[$re['id']] ?? [];
                $re['detail'] = array_filter($details, function ($v) use ($re){return $v['after_id'] == $re['id'];});
            }
        }

        return $res;
    }

    /**
     * Notes: 拒绝售后申请
     * Author: Bruce.z
     * DateTime: 2022/8/22 9:27
     * @param string $number
     * @param string $reason
     * @return bool
     * @throws BaseException
     */
    public function refuse(string $number, string $reason): bool
    {
        $after = $this->getOne(['number'=>$number], ['id','status','oid','member_id']);
        if($after['status'] != AfterSaleConstants::STATUS_NOT_AUDIT){
            throw new BaseException(BaseException::BASE_ERROR, '售后单状态错误!');
        }

        $member = $this->memberService->getOne(['id'=>$after['member_id']], ['id','username','tel']);

        $log = [
            'after_id'=>$after['id'],
            'oid' => $after['oid'],
            'user_id' => $after['member_id'],
            'username' => $member['username'],
            'log_content' => '管理员拒绝售后申请！',
            'log_type' => AfterSaleConstants::LOG_TYPE_PLATFORM,
            'handle_type' => AfterSaleConstants::HANDLE_TYPE_REJECT,
            'log_remark' => $reason,
            'create_time' => time(),
        ];

        DB::beginTransaction();
        try {
            $this->updateByConditions(['number'=>$number],
                [
                    'status'=>AfterSaleConstants::STATUS_AUDIT_REJECT,
                    'cause'=>$reason,
                    'audit_time'=>time()
                ]
            );

            $this->orderRepository->updateByConditions(['oid'=>$after['oid']], [
                'after_status'=>OrderConstant::ORDER_AFTER_STATUS_FINISH,
            ]);

            $this->orderDetailRepository->updateByConditions(['oid'=>$after['oid']], [
                'after_status'=>OrderConstant::ORDER_AFTER_STATUS_FINISH,
            ]);

            $this->afterLogRepository->baseAdd($log);
            DB::commit();
        }catch (Exception $e){
            DB::rollBack();
            Log::getInstance()->error('拒绝售后单异常',[$e->getMessage()]);
            return false;
        }

        return true;
    }

    /**
     * Notes: 同意退款到余额
     * Author: Bruce.z
     * DateTime: 2022/8/22 11:23
     * @param string $number
     * @return bool
     * @throws BaseException
     */
    public function agree(string $number): bool
    {
        $after = $this->getOne(['number'=>$number], ['id','status','oid','member_id']);
        if($after['status'] != AfterSaleConstants::STATUS_NOT_AUDIT){
            throw new BaseException(BaseException::BASE_ERROR, '售后单状态错误!');
        }

        $member = $this->memberService->getOne(['id'=>$after['member_id']], ['id','username','tel']);
        $draw = $this->afterDrawbackRepository->getOne(['after_id'=>$after['id']],['after_id','oid','back_money']);
        $log = [
            'after_id'=>$after['id'],
            'oid' => $after['oid'],
            'user_id' => $after['member_id'],
            'username' => $member['username'],
            'log_content' => '管理员同意售后申请！',
            'log_type' => AfterSaleConstants::LOG_TYPE_PLATFORM,
            'handle_type' => AfterSaleConstants::HANDLE_TYPE_AUDIT,
            'log_remark' => '管理员同意售后申请',
            'create_time' => time(),
        ];

        DB::beginTransaction();
        try {
            $this->updateByConditions(['number'=>$number],['status'=>AfterSaleConstants::STATUS_STAY_DRAWBACK,'audit_time'=>time()]);

            $this->orderRepository->updateByConditions(['oid'=>$after['oid']], [
                'after_status'=>OrderConstant::ORDER_AFTER_STATUS_FINISH,
            ]);

            $this->orderDetailRepository->updateByConditions(['oid'=>$after['oid']], [
                'after_status'=>OrderConstant::ORDER_AFTER_STATUS_FINISH,
            ]);

            $this->afterDrawbackRepository->updateByConditions(['after_id'=>$after['id']], ['status'=>AfterSaleConstants::AFTER_BACK_YES]);

            if($draw['back_money'] >= 0){
                // v1.0 退款到用户钱包
                $this->memberBalanceService->afterMoney($after['member_id'], $draw['back_money'], $after['oid']);
            }

            $this->afterLogRepository->baseAdd($log);

            DB::commit();
        }catch (Exception $e){
            DB::rollBack();
            Log::getInstance()->error('操作失败', [$e->getMessage()]);
            throw new BaseException(BaseException::BASE_ERROR, $e->getMessage());
        }

        return true;
    }

    /**
     * Notes: A端售后订单详情
     * Author: Bruce.z
     * DateTime: 2022/8/22 17:37
     * @param string $number
     * @return array
     * @throws BaseException
     */
    public function info(string $number): array
    {
        $data =  $this->appDetail($number);
        $data['order'] = $this->orderRepository->getOne(['oid'=>$data['oid']], ['order_pay_time','member_id','total_price']);
        $data['member'] = $this->memberService->getOne(['id'=>$data['order']['member_id']], ['id','username','tel']);

        return  $data;
    }


    /**
     * Notes: 退款准备信息
     * Author: Bruce.z
     * DateTime: 2022/10/28 17:51
     * @param int $order_detail_id
     * @return array
     */
    public function applyPre(int $order_detail_id): array
    {
        $re = $this->orderDetailRepository->getOne(['id'=>$order_detail_id], ['goods_id','goods_name','num','spec','id','oid','retail_price','return_num','total_price','price','product_image','product_id']);

        $order = $this->orderRepository->getOne(['oid'=>$re['oid']], ['oid','price','goods_price']);
        $re['return_one'] = round((($re['total_price']*$order['price'])/$order['goods_price']) / $re['num'], 2);
        return $re;
        //$this->orderRepository->getOne(['oid'=>$detail['oid']], []);
    }
}
